package xin.marcher.module.replenished.service.impl;

import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import xin.marcher.framework.common.util.data.DataCuttingUtil;
import xin.marcher.module.common.constants.CoreConstant;
import xin.marcher.module.common.constants.diplomacy.AbstractRedisKeyConstants;
import xin.marcher.module.common.constants.replenished.AvailableConstants;
import xin.marcher.module.common.core.PageResult;
import xin.marcher.module.common.enums.seller.SellerGroupStatusEnum;
import xin.marcher.module.common.enums.seller.SellerInfoStatusEnum;
import xin.marcher.module.common.enums.seller.SellerTypeEnum;
import xin.marcher.module.common.utils.JsonUtil;
import xin.marcher.module.replenished.converter.AvailableConverter;
import xin.marcher.module.replenished.domain.bo.AttributeExtendBO;
import xin.marcher.module.replenished.domain.dto.SkuSellerRelationDTO;
import xin.marcher.module.replenished.domain.entity.AttributeExtendDO;
import xin.marcher.module.replenished.domain.entity.SkuStockSellerRelationDO;
import xin.marcher.module.replenished.domain.request.AvailableRequest;
import xin.marcher.module.replenished.redis.RedisReadWriteManager;
import xin.marcher.module.replenished.redis.RedisSortedSetCache;
import xin.marcher.module.replenished.remote.SellerRemote;
import xin.marcher.module.replenished.repository.ProductRelationRepository;
import xin.marcher.module.replenished.repository.ProductRepository;
import xin.marcher.module.replenished.repository.RedisManagerRepository;
import xin.marcher.module.replenished.service.AvailableService;
import xin.marcher.module.seller.domain.dto.SellerInfoDTO;
import xin.marcher.module.seller.domain.response.SellerGroupResponse;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商品可售业务实现类
 *
 * 
 */
@Service
public class AvailableServiceImpl implements AvailableService {

    @Resource
    private ProductRepository productRepository;

    @Resource
    private ProductRelationRepository productRelationRepository;

    @Resource
    private SellerRemote sellerRemote;

    @Resource
    private RedisReadWriteManager redisReadWriteManager;

    @Resource
    private AvailableConverter availableConverter;

    @Resource
    private RedisManagerRepository redisManagerRepository;

    @Override
    public Boolean syncAvailableProduct(AvailableRequest request) {

        // 分页查询商品信息，处理商品可售的数据
        Integer pageNo = 1;
        // 1.获取卖家组信息列表
        List<SellerGroupResponse> sellerGroupList = querySellerGroupList(pageNo, request.getSellerGroupType());
        // 自营还是POP可售的skuId集合
        Map<Integer, List<String>> sellerTypeSkuIdMap = new HashMap<>();
        while (!CollectionUtils.isEmpty(sellerGroupList)) {
            // 2.对卖家组状态非有效的进行过滤
            List<SellerGroupResponse> effectiveSellerGroupList = sellerGroupFilter(sellerGroupList);

            // 3.根据卖家组列表获取卖家组所支持售卖的商品
            List<SkuSellerRelationDTO> saleProductList = querySaleProductList(effectiveSellerGroupList);

            // 4.获取自营可售商品的且库存充足的信息
            Map<Long, String> sellerInStockMap = querySellerInStockProductMap(saleProductList);

            // 5.构建卖家可售商品信息
            Map<Long, List<String>> sellerSaleProductMap =
                    buildSellerAvailableProduct(sellerInStockMap, effectiveSellerGroupList, saleProductList);

            // 6.对商品中屏蔽卖家的扩展信息进行筛选
            sellerSaleProductMap = sellerFilter(sellerSaleProductMap, saleProductList);

            // 7.合并卖家类型的可售商品
            mergeSellerTypeSkuIdMap(sellerTypeSkuIdMap, saleProductList, sellerSaleProductMap);

            // 8.读取历史的缓存信息，对已经存在的缓存进行diff处理，需要处理新增或者修改的数据更新缓存
            // 构建数据模型，将卖家可售商品缓存起来 缓存结构 key:"前缀标识+卖家id"，value:"可售商品"
            Map<String, RedisSortedSetCache> sortedSetSourceMap = diffAvailableCache(sellerSaleProductMap, sellerGroupList);

            // 9.刷新缓存信息
            redisReadWriteManager.flushIncrSortedSetMap(sortedSetSourceMap);

            pageNo++;
            sellerGroupList = querySellerGroupList(pageNo, request.getSellerGroupType());
        }
        // 10.将卖家类型可售商品缓存起来 缓存结构 key:"前缀标识+卖家类型"，value:"可售商品"，逻辑与卖家可售商品缓存一致
        // 这里需要将分页查询的卖家组的可售商品合并起来，最后做已经存在的缓存diff处理
        Map<String, RedisSortedSetCache> sortedSetSourceMap = diffSellerTypeAvailableCache(sellerTypeSkuIdMap);
        // 11.刷新缓存信息
        redisReadWriteManager.flushIncrSortedSetMap(sortedSetSourceMap);

        return Boolean.TRUE;
    }

    /**
     * 合并分页查询各个分页的卖家类型的可售商品
     *
     * @param sellerTypeSkuIdMap   合并卖家类型的可售商品
     * @param saleProductList      卖家组所支持售卖的商品
     * @param sellerSaleProductMap 卖家可售商品信息
     */
    private void mergeSellerTypeSkuIdMap(Map<Integer, List<String>> sellerTypeSkuIdMap,
                                         List<SkuSellerRelationDTO> saleProductList,
                                         Map<Long, List<String>> sellerSaleProductMap) {
        // 获取卖家类型的可售商品
        Map<Integer, List<String>> skuIdMap = getSkuIdMap(saleProductList, sellerSaleProductMap);

        // 合并卖家类型的可售商品信息
        for (Map.Entry<Integer, List<String>> entry : skuIdMap.entrySet()) {
            List<String> skuIds = sellerTypeSkuIdMap.computeIfAbsent(entry.getKey(), list -> new ArrayList<>());
            skuIds.addAll(entry.getValue());
        }
    }

    /**
     * 对 已经缓存的历史数据进行diff处理，返回需要变更修改的对象刷新缓存
     *
     * @param sellerTypeSkuIdMap 待缓存的数据
     * @return
     */
    private Map<String, RedisSortedSetCache> diffSellerTypeAvailableCache(Map<Integer, List<String>> sellerTypeSkuIdMap) {
        // 获取所有类型
        Set<Integer> sellerTypes = SellerTypeEnum.toMap().keySet();

        // 获取所有类型缓存中的数据
        Map<Integer, List<String>> redisSetMap = redisReadWriteManager.getRedisSortedSet(sellerTypes,
                AbstractRedisKeyConstants::getSellerTypeSaleSkuZsetKey);

        // 进行数据差集处理
        return redisManagerRepository.diffAvailableCache(sellerTypeSkuIdMap, redisSetMap,
                AbstractRedisKeyConstants::getSellerTypeSaleSkuZsetKey);
    }

    /**
     * 获取卖家类型的可售商品
     *
     * @param saleProductList      卖家组所支持售卖的商品
     * @param sellerSaleProductMap 卖家可售商品信息
     * @return
     */
    private Map<Integer, List<String>> getSkuIdMap(List<SkuSellerRelationDTO> saleProductList,
                                                   Map<Long, List<String>> sellerSaleProductMap) {

        Map<String, Integer> skuSellerTypeMap = saleProductList.stream()
                .collect(Collectors.toMap(SkuSellerRelationDTO::getSkuId,
                        SkuSellerRelationDTO::getSellerType, (key1, key2) -> key1));


        Set<String> allSaleProductSet = new HashSet<>(saleProductList.size());

        for (Map.Entry<Long, List<String>> entry : sellerSaleProductMap.entrySet()) {
            allSaleProductSet.addAll(entry.getValue());
        }

        return allSaleProductSet.stream().collect(Collectors.groupingBy(skuSellerTypeMap::get));

    }


    /**
     * 批量查询出对应的可售商品属性扩展信息
     *
     * @param skuSellerRelationDTOS
     * @return
     */
    private List<AttributeExtendDO> querySkuAttributeList(List<SkuSellerRelationDTO> skuSellerRelationDTOS) {
        // 获取商品属性扩展信息
        if (!CollectionUtils.isEmpty(skuSellerRelationDTOS)) {
            // 先获取到对应的skuID列表
            Set<String> skuIdList =
                    skuSellerRelationDTOS.stream().map(SkuSellerRelationDTO::getSkuId).collect(Collectors.toSet());

            // 一次最大查询1000 skuId，多个分页查询,这里做数据切割
            List<Set<String>> splitList = DataCuttingUtil.dataCuttingString(skuIdList, AvailableConstants.SKU_ID_LIMIT_NUM);

            List<AttributeExtendDO> productAttributeAllList = new ArrayList<>(skuIdList.size());
            for (Set<String> skuIds : splitList) {
                List<AttributeExtendDO> attributeExtendDOS = productRepository.queryProductAttributeList(skuIds);
                if (!CollectionUtils.isEmpty(attributeExtendDOS)) {
                    productAttributeAllList.addAll(attributeExtendDOS);
                }
            }
            // 查询返回商品属性扩展信息
            return productAttributeAllList;
        }
        return new ArrayList<>();
    }


    /**
     * 对微仓被屏蔽的卖家进行过滤
     *
     * @param sellerSaleProductMap
     * @param saleProductList
     * @return
     */
    private Map<Long, List<String>> sellerFilter(Map<Long, List<String>> sellerSaleProductMap, List<SkuSellerRelationDTO> saleProductList) {
        // 查询可售商品的属性信息
        List<AttributeExtendDO> skuAttributeDOList = querySkuAttributeList(saleProductList);
        Map<String, AttributeExtendDO> skuAttributeMap = skuAttributeDOList.stream()
                .collect(Collectors.toMap(AttributeExtendDO::getParticipateId, Function.identity()));

        for (Map.Entry<Long, List<String>> entry : sellerSaleProductMap.entrySet()) {
            Long sellerId = entry.getKey();
            Iterator<String> iterator = entry.getValue().iterator();
            while (iterator.hasNext()) {
                String skuId = iterator.next();
                AttributeExtendDO attributeExtendDO = skuAttributeMap.get(skuId);
                if (attributeExtendDO != null && StringUtils.hasLength(attributeExtendDO.getAttributeContent())) {
                    if (!checkShieldingSellerId(attributeExtendDO.getAttributeContent(), sellerId)) {
                        iterator.remove();
                    }
                }
            }
        }

        return sellerSaleProductMap;
    }

    /**
     * 对商品是否屏蔽微仓进行校验
     *
     * @param attributeContent
     * @param sellerId
     * @return
     */
    private Boolean checkShieldingSellerId(String attributeContent, Long sellerId) {
        // 转换为扩展信息对象
        AttributeExtendBO attributeExtendBO = JsonUtil.json2Object(attributeContent, AttributeExtendBO.class);
        // 验证是否命中屏蔽微仓，命中说明需要过滤
        if (Objects.isNull(attributeExtendBO) || StringUtils.isEmpty(attributeExtendBO.getShieldingSellerId())) {
            return true;
        }
        List<String> sellerIds = Arrays.asList(attributeExtendBO.getShieldingSellerId().split(CoreConstant.COMMA));
        return !sellerIds.contains(String.valueOf(sellerId));
    }


    /**
     * 对卖家组状态非有效的进行过滤
     *
     * @param sellerInfoResponseList
     * @return
     */
    private List<SellerGroupResponse> sellerGroupFilter(List<SellerGroupResponse> sellerInfoResponseList) {
        // 过滤无效的卖家组信息
        return sellerInfoResponseList.stream()
                .filter(sellerGroupResponse -> SellerGroupStatusEnum.EFFECTIVE_STATUS.getCode().equals(sellerGroupResponse.getSellerGroupStatus()))
                .collect(Collectors.toList());
    }

    /**
     * 对 已经缓存的历史数据进行diff处理，返回需要变更修改的对象刷新缓存
     *
     * @param sellerSaleProductMap 待缓存的数据
     * @param sellerGroupList      所有的缓存key数据
     * @return
     */
    private Map<String, RedisSortedSetCache> diffAvailableCache(Map<Long, List<String>> sellerSaleProductMap,
                                                                List<SellerGroupResponse> sellerGroupList) {
        // 卖家组包含的所有卖家id
        Set<Long> sellerIds = new HashSet<>(AvailableConstants.INITIAL_CAPACITY);
        for (SellerGroupResponse sellerGroupResponse : sellerGroupList) {
            if (!CollectionUtils.isEmpty(sellerGroupResponse.getSellerInfoDTOList())) {
                sellerIds.addAll(
                        sellerGroupResponse.getSellerInfoDTOList().stream()
                                .map(dto -> dto.getSellerId().longValue())
                                .collect(Collectors.toSet())
                );
            }
        }

        // 缓存中的数据
        Map<Long, List<String>> redisSetMap = redisReadWriteManager.getRedisSortedSet(sellerIds,
                AbstractRedisKeyConstants::getSellerSaleSkuZsetKey);

        // 进行数据差集处理
        return redisManagerRepository.diffAvailableCache(sellerSaleProductMap, redisSetMap,
                AbstractRedisKeyConstants::getSellerSaleSkuZsetKey);
    }

    /**
     * 获取所有卖家组列表
     *
     * @param pageNo
     * @return
     */
    private List<SellerGroupResponse> querySellerGroupList(Integer pageNo, Integer sellerGroupType) {
        // 调用查询卖家组信息接口，获取卖家组信息列表，一次最多查询10个卖家组
        PageResult<SellerGroupResponse> sellerGroupPage =
                sellerRemote.getSellerGroupList(pageNo, AvailableConstants.SELLER_LIMIT_NUM, sellerGroupType);

        return sellerGroupPage.getContent();
    }


    /**
     * 根据卖家组获取可售商品数据
     *
     * @param sellerGroupList
     * @return
     */
    public List<SkuSellerRelationDTO> querySaleProductList(List<SellerGroupResponse> sellerGroupList) {
        if (CollectionUtils.isEmpty(sellerGroupList)) {
            return new ArrayList<>();
        }

        // 获取卖家组id列表
        List<Long> sellerGroupIds = sellerGroupList.stream()
                .map(response -> response.getSellerGroupId().longValue())
                .collect(Collectors.toList());

        // 返回卖家组可售商品
        return availableConverter.convertDTOList(productRelationRepository.queryAvailableProduct(sellerGroupIds));
    }


    /**
     * 构建卖家可售商品数据
     *
     * @param sellerInStockMap
     * @param sellerGroupList
     * @param saleProductList
     * @return
     */
    public Map<Long, List<String>> buildSellerAvailableProduct(Map<Long, String> sellerInStockMap,
                                                               List<SellerGroupResponse> sellerGroupList,
                                                               List<SkuSellerRelationDTO> saleProductList) {
        // key为卖家组id，value为卖家组信息
        Map<Long, SellerGroupResponse> sellerGroupMap = sellerGroupList.stream()
                .collect(Collectors.toMap(response -> response.getSellerGroupId().longValue(), Function.identity()));

        // 卖家可售商品列表，key为卖家id，value为卖家可售商品skuId列表
        // 卖家组是分页查询，一次最多查询10个卖家组，卖家组对应的卖家一般最多就是几十个，这里初始大小设定256，避免频繁扩容
        Map<Long, List<String>> sellerSaleProductMap = new HashMap<>(AvailableConstants.INITIAL_CAPACITY);

        // 遍历所有卖家组可售商品信息
        for (SkuSellerRelationDTO skuSellerRelationDTO : saleProductList) {
            // 卖家组信息
            SellerGroupResponse sellerGroupResponse = sellerGroupMap.get(skuSellerRelationDTO.getSellerGroupId());
            // 遍历卖家组包含的卖家信息
            for (SellerInfoDTO sellerInfoDTO : sellerGroupResponse.getSellerInfoDTOList()) {
                if (SellerInfoStatusEnum.CLOSE_STATUS.getCode().equals(sellerInfoDTO.getSellerStatus())) {
                    // 过滤掉闭店卖家
                    continue;
                }

                // 卖家可售商品信息
                Long sellerId = sellerInfoDTO.getSellerId().longValue();
                List<String> skuIds = sellerSaleProductMap.computeIfAbsent(sellerId, list -> new ArrayList<>());

                // 自营商品需要判断库存是否大于0，大于0才可售，非自营商品不判断库存
                String skuId = skuSellerRelationDTO.getSkuId();
                if (SellerTypeEnum.SELF.getCode().equals(skuSellerRelationDTO.getSellerType())) {
                    // 自营商品判断库存
                    if (checkProductStock(sellerInStockMap, sellerId, skuId)) {
                        skuIds.add(skuId);
                    }
                } else {
                    // 添加可售商品
                    skuIds.add(skuId);
                }
            }
        }
        return sellerSaleProductMap;
    }

    /**
     * 判断指定卖家的指定商品是否有库存
     *
     * @param sellerInStockMap
     * @param sellerId
     * @param skuId
     * @return
     */
    private Boolean checkProductStock(Map<Long, String> sellerInStockMap, Long sellerId, String skuId) {
        String skuIdArray = sellerInStockMap.get(sellerId);
        return StringUtils.hasLength(skuIdArray) && skuIdArray.contains(skuId);
    }

    /**
     * 查询自营卖家商品有库存的数据
     *
     * @param saleProductList
     * @return
     */
    private Map<Long, String> querySellerInStockProductMap(List<SkuSellerRelationDTO> saleProductList) {
        if (CollectionUtils.isEmpty(saleProductList)) {
            return Maps.newHashMap();
        }

        // 可售skuId
        List<String> saleSkuIds = saleProductList.stream()
                .map(SkuSellerRelationDTO::getSkuId)
                .collect(Collectors.toList());

        // 卖家组自营且有库存的可售商品
        List<SkuStockSellerRelationDO> skuStockSellerRelationAllList = new ArrayList<>(saleSkuIds.size());

        // 一次最大查询1000 skuId，多个分页查询,这里做数据切割
        List<List<String>> splitList =
                DataCuttingUtil.dataCuttingString(saleSkuIds, AvailableConstants.SKU_ID_LIMIT_NUM);

        // 分页查询卖家组自营商品库存大于0的数据
        for (List<String> skuIds : splitList) {
            List<SkuStockSellerRelationDO> skuStockSellerRelationDOS =
                    productRelationRepository.querySellerInStockProductList(skuIds);
            if (!CollectionUtils.isEmpty(skuStockSellerRelationDOS)) {
                skuStockSellerRelationAllList.addAll(skuStockSellerRelationDOS);
            }
        }

        // 所有自营可售且库存大于0的商品，key为卖家id，value为可售商品
        Map<Long, String> sellerInStockMap =
                skuStockSellerRelationAllList.stream().collect(Collectors.toMap(SkuStockSellerRelationDO::getSellerId,
                        SkuStockSellerRelationDO::getSkuId, (key1, key2) -> String.join(CoreConstant.COMMA, key1, key2)));

        return sellerInStockMap;
    }
}
